/****************************************************************************
*                                     *                                     *
*  Jeff Molofee's IPicture Basecode   *    Huge Thanks To: Dave Richards    *
*       http://nehe.gamedev.net       *                    Bobby Ward &     *
*                2002                 *                    The MSDN         *
*                                     *                                     *
*****************************************************************************
*                                                                           *
*   Loads  : BMP, EMF, GIF, ICO, JPG, WMF                                   *
*   Source : Reads From Disk Or The Internet                                *
*   Extras : Images Can Be Any Width Or Height                              *
*                                                                           *
*****************************************************************************
*                                                                           *
*   ReshapeGL  : Set Your Aspect Ratio, How You Want                        *
*   WindowProc : Add Custom WM_ Events (Mouse, Etc)                         *
*   WinMain    : Set The Window Title                                       *
*                Set Resolution & Color Depth                               *
*                Remove 4 Lines Of Code To Force Fullscreen (Commented)     *
*                                                                           *
*****************************************************************************
*                                                                           *
*   Free To Use In Projects Of Your Own.  All I Ask For Is A Simple Greet   *
*   Or Mention Of The Site In Your Readme Or The Project Itself :)          *
*                                                                           *
****************************************************************************/

#include <windows.h>													// Header File For Windows
#include <stdio.h>
#include <gl\gl.h>														// Header File For The OpenGL32 Library
#include <gl\glext.h>
#include <math.h>														// Header File For The Math Library			(Used In BuildTexture)

#include "NeHeGL.h"														// Header File For NeHeGL
#include "Texturing.h"
#include "Register-Combiners.h"
#include "Primitives.h"

#pragma comment( lib, "opengl32.lib" )									// Search For OpenGL32.lib While Linking
#pragma comment( lib, "glu32.lib" )										// Search For GLu32.lib While Linking

#define NUM_LISTS 2
#define NUM_TEXTURES 3

GL_Window*	g_window;													// Window Structure
Keys*		g_keys;														// Keyboard

// User Defined Variables
GLfloat	xrot;															// X Rotation							
GLfloat	yrot;															// Y Rotation							
GLfloat	zrot;															// Z Rotation							

float shadow_matrix[16];

float light_pos[] = { 0.0f, 8.0f, -5.0f }; // Coordinates of the light source
float normal_vec[] = { 0.0f,  -1.0f, 0.0f }; // Normal vector for the plane
float plane_point[] = { 0.0f,-1.0f, -20.0f }; // Point of the plane

float         PPL_s, PPL_t, PPL_r;
const float   Light_Radius = 10.0f;
const float   Light_Color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
/*
typedef struct
{
	GLfloat x,y,z;
}Vector3D;

typedef struct
{
	GLfloat u,v;
}Vector2D;

Vector3D cube_verts[] = {
	{	-1.0f, -1.0f,  1.0f	},	//Frontface
	{	1.0f, -1.0f,  1.0f	},
	{	 1.0f,  1.0f,  1.0f	},
	{   -1.0f,  1.0f,  1.0f	},

	{	-1.0f, -1.0f,	-1.0f,	},	//Backface
	{	-1.0f,	1.0f,	-1.0f,	},
	{	 1.0f,  1.0f,	-1.0f,	},
	{    1.0f, -1.0f,	-1.0f,	},

	{	-1.0f,	1.0f,	-1.0f,	},	//Topface 
	{	-1.0f,	1.0f,	 1.0f,	},
	{	1.0f,	1.0f,	 1.0f,	},
	{	1.0f,	1.0f,	-1.0f,	},

	{	-1.0f,	-1.0f,  -1.0f,	},	//Bottom face
	{	1.0f,	-1.0f,	-1.0f,	},
	{	1.0f,	-1.0f,	1.0f,	},
	{	-1.0f,	-1.0f,	1.0f,	},

	{	-1.0f,	-1.0f,	-1.0f,	},	//Left face
	{	-1.0f,	-1.0f,	1.0f,	},
	{	-1.0f,	1.0f,	1.0f,	},
	{	-1.0f,	1.0f,	-1.0f,	},

	{	1.0f,	-1.0f,	-1.0f,	},	//Right face
	{	1.0f,	 1.0f,	-1.0f,	},
	{	1.0f,	 1.0f,	1.0f,	},
	{	1.0f,	-1.0f,	1.0f,	},
};

Vector2D tex_coords[] = {
	{	0.0,	1.0f,	},
	{	1.0f,	1.0f,	},
	{	1.0f,	0.0f,	},
	{	0.0f,	0.0f,	},

	{	1.0,	0.0f,	},
	{	0.0f,	0.0f,	},
	{	0.0f,	1.0f,	},
	{	1.0f,	1.0f,	},

	{	0.0f,	1.0f,	},
	{	0.0f,	0.0f,	},
	{	1.0f,	0.0f,	},
	{	1.0f,	1.0f,	},

	{	0.0f,	1.0f,	},
	{	0.0f,	0.0f,	},
	{	1.0f,	0.0f,	},
	{	1.0f,	1.0f,	},

	{	0.0f,	1.0f,	},
	{	0.0f,	0.0f,	},
	{	1.0f,	0.0f,	},
	{	1.0f,	1.0f,	},

	{	0.0f,	1.0f,	},
	{	0.0f,	0.0f,	},
	{	1.0f,	0.0f,	},
	{	1.0f,	1.0f,	},

};
*/
bool s3tc=true;

GLuint  list[NUM_LISTS];
GLuint	texture[NUM_TEXTURES];														// Three Textures						

TEXTURE myTex;
PRIMITIVE myPrimitive;

void SetShadowProjection(float * l, float * e, float * n);

PFNGLMULTITEXCOORD2FARBPROC		glMultiTexCoord2fARB	 = 0;
PFNGLACTIVETEXTUREARBPROC		glActiveTextureARB		 = 0;
PFNGLCLIENTACTIVETEXTUREARBPROC	glClientActiveTextureARB = 0;

PFNGLCOMBINERPARAMETERFVNV glCombinerParameterfvNV;
PFNGLCOMBINERPARAMETERIVNV glCombinerParameterivNV;
PFNGLCOMBINERPARAMETERFNV glCombinerParameterfNV;
PFNGLCOMBINERPARAMETERINV glCombinerParameteriNV;
PFNGLCOMBINERINPUTNV glCombinerInputNV;
PFNGLCOMBINEROUTPUTNV glCombinerOutputNV;
PFNGLFINALCOMBINERINPUTNV glFinalCombinerInputNV;

PFNGLGETCOMBINERINPUTPARAMETERFVNV glGetCombinerInputParameterfvNV;
PFNGLGETCOMBINERINPUTPARAMETERIVNV glGetCombinerInputParameterivNV;
PFNGLGETCOMBINEROUTPUTPARAMETERFVNV glGetCombinerOutputParameterfvNV;
PFNGLGETCOMBINEROUTPUTPARAMETERIVNV glGetCombinerOutputParameterivNV;
PFNGLGETFINALCOMBINERINPUTPARAMETERFVNV glGetFinalCombinerInputParameterfvNV;
PFNGLGETFINALCOMBINERINPUTPARAMETERIVNV glGetFinalCombinerInputParameterivNV;

PFNGLLOCKARRAYSEXTPROC		glLockArraysEXT		= NULL;
PFNGLUNLOCKARRAYSEXTPROC	glUnlockArraysEXT	= NULL;

float GetFPS(void) 
{
	static float frames_per_second = 60;
	static int starttime,endtime,counter;

	if(counter == 10) 
	{
		endtime = starttime;
		starttime = GetTickCount();
		frames_per_second = (float)(counter * 1000.0 / (starttime - endtime));
		counter = 0;
	}
	counter++;
	return frames_per_second;
}

bool InitExtensions()
{
    
	// The name of the extension
	char *Extension;

    Extension = (char *) glGetString(GL_EXTENSIONS);
   
    if (!(strstr(Extension, "GL_ARB_multitexture")) == 1)
	{ 
			MessageBox(NULL,"'GL_ARB_multitexture'","ERROR : Extension not supported :",MB_ICONERROR);
	} 
	else 
	{
			// The "GL_ARB_multitexture" is supported
			
			// MultiTexturing Initialisation
			glMultiTexCoord2fARB     =  (PFNGLMULTITEXCOORD2FARBPROC)     wglGetProcAddress("glMultiTexCoord2fARB");
			glActiveTextureARB       =  (PFNGLACTIVETEXTUREARBPROC)       wglGetProcAddress("glActiveTextureARB");		
			glClientActiveTextureARB =  (PFNGLCLIENTACTIVETEXTUREARBPROC) wglGetProcAddress("glClientActiveTextureARB");
      
			// MultiTexturing Initialisation failed !
			if (!glActiveTextureARB || !glMultiTexCoord2fARB || !glClientActiveTextureARB)
			{
				MessageBox(NULL,"GL_ARB_multitexture","ERROR : Initialisation failed !",MB_ICONERROR);
				return false;
			}
	}
	if (!(strstr(Extension, "GL_NV_register_combiners")) == 1)
	{ 
		MessageBox(NULL,"GL_NV_register_combiners","Extension not supported :",MB_ICONERROR);
		return false;
	} 
	else
	{
		glCombinerParameterfvNV = (PFNGLCOMBINERPARAMETERFVNV) wglGetProcAddress("glCombinerParameterfvNV");
	    glCombinerParameterivNV = (PFNGLCOMBINERPARAMETERIVNV) wglGetProcAddress("glCombinerParameterivNV");
	    glCombinerParameterfNV  = (PFNGLCOMBINERPARAMETERFNV) wglGetProcAddress("glCombinerParameterfNV");
	    glCombinerParameteriNV  = (PFNGLCOMBINERPARAMETERINV) wglGetProcAddress("glCombinerParameteriNV");
	    glCombinerInputNV       = (PFNGLCOMBINERINPUTNV) wglGetProcAddress("glCombinerInputNV");
	    glCombinerOutputNV      = (PFNGLCOMBINEROUTPUTNV) wglGetProcAddress("glCombinerOutputNV");
	    glFinalCombinerInputNV  = (PFNGLFINALCOMBINERINPUTNV) wglGetProcAddress("glFinalCombinerInputNV");
	
	    glGetCombinerInputParameterfvNV      = (PFNGLGETCOMBINERINPUTPARAMETERFVNV) wglGetProcAddress("glGetCombinerInputParameterfvNV");
	    glGetCombinerInputParameterivNV      = (PFNGLGETCOMBINERINPUTPARAMETERIVNV) wglGetProcAddress("glGetCombinerInputParameterivNV");
	    glGetCombinerOutputParameterfvNV     = (PFNGLGETCOMBINEROUTPUTPARAMETERFVNV) wglGetProcAddress("glGetCombinerOutputParameterfvNV");
	    glGetCombinerOutputParameterivNV     = (PFNGLGETCOMBINEROUTPUTPARAMETERIVNV) wglGetProcAddress("glGetCombinerOutputParameterivNV");
	    glGetFinalCombinerInputParameterfvNV = (PFNGLGETFINALCOMBINERINPUTPARAMETERFVNV) wglGetProcAddress("glGetFinalCombinerInputParameterfvNV");
	    glGetFinalCombinerInputParameterivNV = (PFNGLGETFINALCOMBINERINPUTPARAMETERIVNV) wglGetProcAddress("glGetFinalCombinerInputParameterivNV");
	}
	if (!(strstr(Extension, "GL_EXT_texture_compression_s3tc")) == 1)
	{ 
		s3tc=false;
	} 

	glLockArraysEXT		= (PFNGLLOCKARRAYSEXTPROC)		wglGetProcAddress("glLockArraysEXT");
	glUnlockArraysEXT	= (PFNGLUNLOCKARRAYSEXTPROC)	wglGetProcAddress("glUnlockArraysEXT");

	if(glLockArraysEXT == NULL  ||  glUnlockArraysEXT == NULL)
	{
	 return false;
	}


	return true;
}

bool SetupRegisterCombiners()
{
	if(InitExtensions())
	{
	  glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, 1);

	  glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, (float *) &Light_Color);

	  glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
	  glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB);
	  glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
	  glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB);
	  
	  glCombinerOutputNV(GL_COMBINER0_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV, GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE);

	  glFinalCombinerInputNV(GL_VARIABLE_A_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
	  glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
	  glFinalCombinerInputNV(GL_VARIABLE_C_NV, GL_CONSTANT_COLOR0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
	  glFinalCombinerInputNV(GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
	  glFinalCombinerInputNV(GL_VARIABLE_G_NV, GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_ALPHA);

	  glEnable(GL_REGISTER_COMBINERS_NV);

	  return true;
	}
	else
		return false;
}

void ProcessVertex_PPL(float x, float y, float z)
{
	PPL_s = (x - light_pos[0]) / (Light_Radius) + 0.5f;
	PPL_r = (y - light_pos[1]) / (Light_Radius) + 0.5f;
	PPL_t = (z - light_pos[2]) / (Light_Radius) + 0.5f;
	
	glMultiTexCoord2fARB(GL_TEXTURE0_ARB, PPL_s, PPL_t);
	glMultiTexCoord2fARB(GL_TEXTURE1_ARB, PPL_r, 0.5f);

	glVertex3f(x, y, z);
}

void MakeDisplayLists(void)
{
	list[0]=glGenLists(1);
	glNewList(list[0],GL_COMPILE);
	 glBindTexture(GL_TEXTURE_2D, texture[1]);
	 myPrimitive.DrawCube();
	glEndList();

	list[1]=list[0]+1;
	glNewList(list[1],GL_COMPILE);
	 glActiveTextureARB(GL_TEXTURE1_ARB);
      glDisable(GL_TEXTURE_2D);

     glDisable(GL_REGISTER_COMBINERS_NV);

	 glBlendFunc(GL_DST_COLOR, GL_ZERO);

	 glActiveTextureARB(GL_TEXTURE0_ARB);
	  glEnable(GL_TEXTURE_2D);


	 glBindTexture(GL_TEXTURE_2D, texture[0]);
	 glBegin(GL_QUADS);																																			
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  0.0f, -1.0f);												
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  0.0f,  1.0f);												
		glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  0.0f,  1.0f);												
		glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  0.0f, -1.0f);
	 glEnd();

    glEndList();
}

BOOL Initialize (GL_Window* window, Keys* keys)							// Any GL Init Code & User Initialiazation Goes Here
{
	g_window	= window;												// Window Values
	g_keys		= keys;													// Key Values

	glEnable(GL_TEXTURE_2D);											// Enable Texture Mapping				
	glClearColor (0.0f, 0.05f, 0.1f, 0.5f);								// Black Background						// (Set To Any Color You Wish)
	glDepthFunc (GL_LEQUAL);											// The Type Of Depth Testing			// (Select The Depth Testing You Want)
	glEnable (GL_DEPTH_TEST);											// Enable Depth Testing
	glShadeModel (GL_SMOOTH);											// Select Smooth Shading				// (Set To Flat Shading If You Wish)
	glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);					// Set Perspective Calculations To Most Accurate

	glEnable(GL_CULL_FACE);
	glEnable(GL_BLEND);
	glCullFace(GL_BACK);

	glLineWidth(4.0f);

	if(!SetupRegisterCombiners())
		return false;

	myTex.Init(GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, s3tc);

	if((!myTex.Generate(TEX_2D, "Data//Floor.jpg",0,texture[0]))    ||
	   (!myTex.Generate(TEX_2D, "Data//boxes.jpg",0,texture[1]))    ||
	   (!myTex.Generate(TEX_2D, "Data//Light2D.bmp",0,texture[2])) 
	  )	
	  return false;

	myPrimitive.MakeCube();
	glLockArraysEXT(0, 24);

	MakeDisplayLists();

	SetShadowProjection(light_pos,plane_point,normal_vec);

	return TRUE;														// Return TRUE (Initialization Successful)
}

void Deinitialize (void)												// Any User DeInitialization Goes Here
{
	for(int i=0;i<NUM_LISTS;i++)
	 glDeleteLists(list[i], 1);

	glDeleteTextures(NUM_TEXTURES,texture);
}

void Update (float milliseconds)										// Perform Motion Updates Here
{
	if (g_keys->keyDown [VK_ESCAPE])									// Is ESC Being Pressed?
		TerminateApplication (g_window);								// Terminate The Program

	if (g_keys->keyDown [VK_F1])										// Is F1 Being Pressed?
		ToggleFullscreen (g_window);									// Toggle Fullscreen Mode

	// only recalc the shadow matrix when the light is moved
	if (g_keys->keyDown [VK_UP])
	{
		SetShadowProjection(light_pos,plane_point,normal_vec);
		light_pos[2]-=0.1f;
	}
	if (g_keys->keyDown [VK_DOWN])
	{
		SetShadowProjection(light_pos,plane_point,normal_vec);
		light_pos[2]+=0.1f;
	}
	if (g_keys->keyDown [VK_LEFT])
	{
		SetShadowProjection(light_pos,plane_point,normal_vec);
		light_pos[0]-=0.1f;
	}
	if (g_keys->keyDown [VK_RIGHT])
	{
		SetShadowProjection(light_pos,plane_point,normal_vec);
		light_pos[0]+=0.1f;
	}
	if (g_keys->keyDown [VK_PRIOR])
	{
		SetShadowProjection(light_pos,plane_point,normal_vec);
		light_pos[1]+=0.1f;
	}
	if (g_keys->keyDown [VK_NEXT])
	{
		SetShadowProjection(light_pos,plane_point,normal_vec);
		light_pos[1]-=0.1f;
	}

	float fps=GetFPS();
	char  fps_string[10];

	sprintf(fps_string,"fps: %f\0",fps );		
	SetWindowText(g_window->hWnd, fps_string);

	xrot+=(float)(milliseconds)/32.0f;									// Increase X Rotation					
	yrot+=(float)(milliseconds)/16.0f;									// Increase Y Rotation					
	zrot+=(float)(milliseconds)/48.0f;									// Increase Z Rotation		
}

void SetShadowProjection(float * l, float * e, float * n)
{
  float d, c;
  //float shadow_matrix[16];

  // These are c and d (corresponding to the tutorial)
  
  d = n[0]*l[0] + n[1]*l[1] + n[2]*l[2];
  c = e[0]*n[0] + e[1]*n[1] + e[2]*n[2] - d;

  // Create the matrix. OpenGL uses column by column
  // ordering

  shadow_matrix[0]  = l[0]*n[0]+c; 
  shadow_matrix[4]  = n[1]*l[0]; 
  shadow_matrix[8]  = n[2]*l[0]; 
  shadow_matrix[12] = -l[0]*c-l[0]*d;
  
  shadow_matrix[1]  = n[0]*l[1];        
  shadow_matrix[5]  = l[1]*n[1]+c;
  shadow_matrix[9]  = n[2]*l[1]; 
  shadow_matrix[13] = -l[1]*c-l[1]*d;
  
  shadow_matrix[2]  = n[0]*l[2];        
  shadow_matrix[6]  = n[1]*l[2]; 
  shadow_matrix[10] = l[2]*n[2]+c; 
  shadow_matrix[14] = -l[2]*c-l[2]*d;
  
  shadow_matrix[3]  = n[0];        
  shadow_matrix[7]  = n[1]; 
  shadow_matrix[11] = n[2]; 
  shadow_matrix[15] = -d;

  // Finally multiply the matrices together *plonk*
  //glMultMatrixf(shadow_matrix);
}

void DrawCube(bool lightmapped)
{
	 glRotatef(xrot,1.0f,0.0f,0.0f);										// Rotate On The X-Axis					
	 glRotatef(yrot,0.0f,1.0f,0.0f);										// Rotate On The Y-Axis					
	 glRotatef(zrot,0.0f,0.0f,1.0f);

	 if(lightmapped==true)
	 {
	 glBlendFunc(GL_ONE, GL_ONE);

	 glActiveTextureARB(GL_TEXTURE0_ARB);
	  glEnable(GL_TEXTURE_2D);
	  glBindTexture(GL_TEXTURE_2D, texture[2]);

	 glActiveTextureARB(GL_TEXTURE1_ARB);
	  glEnable(GL_TEXTURE_2D);
	  glBindTexture(GL_TEXTURE_2D, texture[2]);

	 glBegin(GL_QUADS);													// Begin Drawing Quads																												
		 ProcessVertex_PPL(-1.0f, -1.0f,  1.0f);												
		 ProcessVertex_PPL( 1.0f, -1.0f,  1.0f);												
		 ProcessVertex_PPL( 1.0f,  1.0f,  1.0f);												
		 ProcessVertex_PPL(-1.0f,  1.0f,  1.0f);												
																							
		 ProcessVertex_PPL(-1.0f, -1.0f, -1.0f);												
		 ProcessVertex_PPL(-1.0f,  1.0f, -1.0f);												
		 ProcessVertex_PPL( 1.0f,  1.0f, -1.0f);												
		 ProcessVertex_PPL( 1.0f, -1.0f, -1.0f);												
													// Begin Drawing Quads																												
		 ProcessVertex_PPL(-1.0f,  1.0f, -1.0f);												
		 ProcessVertex_PPL(-1.0f,  1.0f,  1.0f);												
		 ProcessVertex_PPL( 1.0f,  1.0f,  1.0f);												
	     ProcessVertex_PPL( 1.0f,  1.0f, -1.0f);												
		
		 ProcessVertex_PPL(-1.0f, -1.0f, -1.0f);												
		 ProcessVertex_PPL( 1.0f, -1.0f, -1.0f);												
		 ProcessVertex_PPL( 1.0f, -1.0f,  1.0f);												
		 ProcessVertex_PPL(-1.0f, -1.0f,  1.0f);												
	 																						
		 ProcessVertex_PPL( 1.0f, -1.0f, -1.0f);												
		 ProcessVertex_PPL( 1.0f,  1.0f, -1.0f);												
		 ProcessVertex_PPL( 1.0f,  1.0f,  1.0f);												
		 ProcessVertex_PPL( 1.0f, -1.0f,  1.0f);												
																								
		 ProcessVertex_PPL(-1.0f, -1.0f, -1.0f);												
		 ProcessVertex_PPL(-1.0f, -1.0f,  1.0f);												
		 ProcessVertex_PPL(-1.0f,  1.0f,  1.0f);												
		 ProcessVertex_PPL(-1.0f,  1.0f, -1.0f);												
	 glEnd();	

     glActiveTextureARB(GL_TEXTURE1_ARB);
      glDisable(GL_TEXTURE_2D);

     glDisable(GL_REGISTER_COMBINERS_NV);

	 glBlendFunc(GL_DST_COLOR, GL_ZERO);

	 glActiveTextureARB(GL_TEXTURE0_ARB);
	  glEnable(GL_TEXTURE_2D);
	 }
/*
	 glEnableClientState(GL_VERTEX_ARRAY);
	 glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	 glBindTexture(GL_TEXTURE_2D, texture[1]);
	
	 glDrawArrays(GL_QUADS, 0, 24);

	 glDisableClientState(GL_VERTEX_ARRAY);
	 glDisableClientState(GL_TEXTURE_COORD_ARRAY);*/
	 glCallList(list[0]);
}

void DrawFloor()
{
	glTranslatef(0,-3,0);
	glScalef(40,1,40);
	glColor3f(1,1,1);

    glBlendFunc(GL_ONE, GL_ONE);

	 glActiveTextureARB(GL_TEXTURE0_ARB);
	  glEnable(GL_TEXTURE_2D);
	  glBindTexture(GL_TEXTURE_2D, texture[2]);

	 glActiveTextureARB(GL_TEXTURE1_ARB);
	  glEnable(GL_TEXTURE_2D);
	  glBindTexture(GL_TEXTURE_2D, texture[2]);

	glBegin(GL_QUADS);																																			
		ProcessVertex_PPL(-1.0f,  0.0f, -1.0f);												
		ProcessVertex_PPL(-1.0f,  0.0f,  1.0f);												
		ProcessVertex_PPL( 1.0f,  0.0f,  1.0f);												
		ProcessVertex_PPL( 1.0f,  0.0f, -1.0f);
	glEnd();

	glCallList(list[1]);
}

void Draw(void)
{
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);				// Clear Screen And Depth Buffer

	for(int i=0; i<5; i++)
	{
		for(int j=0;j<5;j++)
		{
		 glLoadIdentity ();	
	     glPushMatrix();

		 plane_point[0]=i-2.5f;
		 plane_point[2]=-10.0f-j;

	      glTranslatef(plane_point[0],(float)sin(j),plane_point[2]);										// Translate 5 Units Into The Screen	// (Modify To A Depth You Want)
          glScalef(0.25f, 0.25f, 0.25f);
          glColor3f(1,1,1);			
	 
		  DrawCube(true);
		 glPopMatrix();

		 glPushMatrix();
	      glTranslatef(plane_point[0],plane_point[1],plane_point[2]);  
		  glMultMatrixf(shadow_matrix);
          glColor3f(0.3f,0.3f,0.3f);
		  DrawCube(false);
		 glPopMatrix();
		}
	}

	DrawFloor();

	glLoadIdentity();
	glPushMatrix();

	glDisable(GL_BLEND);
	glDisable(GL_TEXTURE_2D);

	glBegin(GL_LINES);
	 glColor3f(1,0.8f,0.4f);
     glVertex3f(0,-3.5f,-20);
	 glColor3f(1,1,1);
	 glVertex3f(light_pos[0], light_pos[1], light_pos[2]);
	glEnd();

	glEnable(GL_BLEND);
	glEnable(GL_TEXTURE_2D);

	glPopMatrix();

	glFlush ();															// Flush The GL Rendering Pipeline
}
